﻿#include "ISEA4HImpl.cuh"
#include "../Projection/Project.cuh"

using namespace NNU::DGGS::Kernel::Projection;
using namespace NNU::DGGS::Kernel::ISEA4H;

__DGGS_CPGPU__ void CuISEA4HImpl::init()
{
    this->isea = new Project();
}

__DGGS_CPGPU__ void CuISEA4HImpl::release()
{
    delete this->isea;
}

__DGGS_CPGPU__ bool CuISEA4HImpl::decode(DGGSElementCode code, GeoCoord& coord)
{
    double lon = 0;
    double lat = 0;
    switch (code.elementType)
    {
        case DGGSElementType::Voxel:
        case DGGSElementType::Cell:
        {
            this->isea->RC2LBCenter(DGGSGridType::DGGS_ISEA4H, code.basePartition, code.row, code.col, code.level, lon,
                                    lat);
            coord.lon = lon;
            coord.lat = lat;
            break;
        }
        case DGGSElementType::Edge:
        {
            if(code.row==0)
                switch (code.col % 3) {
                case 2:
                    code.col=(code.col + 1) / 3 * 2 - 1;
                case 0:
                    code.col=(code.col - 1) / 3 * 2;
                    break;
                case 1:
                    code.col=(code.col + 1) / 3 * 2 - 1;
                    break;
                }
            else
                switch (code.col % 3) {
                case 0:
                    code.col=(code.col) / 3 * 2;
                    break;
                case 1:
                    code.col=(code.col - 2) / 3 * 2 + 1;
                    break;
                case 2:
                    code.col=(code.col - 1) / 3 * 2;
                    break;
                }
            double vertexes[3];
            this->isea->RC2LBVertex(code.basePartition, code.row, code.col, code.level, DGGSGridType::DGGS_ISEA4H,
                                    vertexes);
            coord.lon = vertexes[0];
            coord.lat = vertexes[1];
            break;
        }
        case DGGSElementType::Vertex:
        {
            double vertexes[3];
            this->isea->RC2LBVertex(code.basePartition, code.row, code.col, code.level, DGGSGridType::DGGS_ISEA4H, vertexes);
            coord.lon = vertexes[0];
            coord.lat = vertexes[1];
            break;
        }
        default:
            printf("Entered a wrong type of element!\n");
            return false;
    }
    return true;
}

__DGGS_CPGPU__ bool CuISEA4HImpl::encode(GeoCoord coord, DGGSElementCode& code)
{
    long long int row, col;
    int basePartition = -1;
    this->isea->LB2RC(coord.lon, coord.lat, code.level, DGGSGridType::DGGS_ISEA4H, basePartition, row, col);

    code.basePartition = basePartition;
    code.elementType = DGGSElementType::Cell;
    code.row = row;
    code.col = col;
    return true;
}
